<?php

namespace magein\think\command;

use magein\think\command\traits\CommandParamParse;
use magein\utils\Faker;
use magein\utils\Result;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
use think\Model;

/**
 * 依赖模型文件
 *
 * 生成mock数据使用模型文件是为了处理模型时间,修改器,获取器等功能
 *
 */
class MakeFaker extends Command
{
    use CommandParamParse;

    protected string $help = '
    创建mock数据,支持缩写,会自动查找model目录下符合的文件名称
    php think model:faker user                      根据model/User.php创建
    php think model:faker user_order                根据model/UserOrder.php创建
    php think model:faker user/user_order           根据model/user/UserOrder.php创建
';

    protected function configure()
    {
        // 指令配置
        $this->setName('model:faker')
            ->addArgument('name')
            ->addOption('limit', 'l', Option::VALUE_OPTIONAL, '生成数量')
            ->addOption('index', 'i', Option::VALUE_OPTIONAL, '选择键')
            ->setDescription('创建模拟数据')
            ->setHelp($this->help);

    }

    protected function execute(Input $input, Output $output)
    {
        if (\think\facade\Env::get('app_env') !== 'local') {
            $output->error('只能在开发环境中使用');
            exit();
        }

        $name = $input->getArgument('name');
        $limit = intval($input->getOption('limit'));
        $index = intval($input->getOption('index'));

        if ($limit <= 0) {
            $limit = 1;
        } elseif ($limit >= 100) {
            $limit = 100;
        }

        $models = $this->findModelByTableName($name);

        if (count($models) > 1) {
            if (empty($index)) {
                $output->writeln('匹配到多个模型,请使用-i参数选择:');
                foreach ($models as $key => $item) {
                    $output->writeln('  ' . $key . ' : ' . $item);
                }
                return false;
            }
            $model_namespace = $models[$index];
        } else {
            $model_namespace = $models[1] ?? '';
        }

        $success = $this->make($model_namespace, $limit);

        if ($success instanceof Result) {
            $output->error($success->getMsg());
        } else {
            // 指令输出
            $output->writeln('创建完成，创建成功数量:' . $success);
        }
    }

    /**
     * 创建数据
     * 允许外部调用
     * @param string $model_namespace
     * @param string|int $limit
     * @return int|Result
     */
    public function make(string $model_namespace, int|string $limit = 1): Result|int
    {
        $limit = intval($limit);
        if ($limit <= 0) {
            $limit = 1;
        } elseif ($limit >= 100) {
            $limit = 100;
        }

        $config = app()->config->get('console.config.faker', []);
        $img_field = ($config['img_field'] ?? '') ?: ['avatar', 'head', 'icon', 'thumb', 'pic', 'pics', 'img', 'image', 'images', 'picture', 'photo'];
        $img_src = ($config['img_src'] ?? []) ?: [];

        $http_field = ($config['http_field'] ?? '') ?: ['url', 'urls', 'redirect', 'http', 'https', 'remote', 'remote_url', 'domain', 'host'];
        $http_url = ($config['http_url'] ?? '') ?: [\think\facade\Env::get('app_url', 'http://localhost')];

        $result = $this->tableAttrs((new $model_namespace())->getName());

        if ($result->getCode()) {
            return $result;
        }

        $table_info = $result->getData();
        $attrs = $table_info['attrs'];

        $success = 0;
        for ($i = 0; $i < $limit; $i++) {
            /**
             * @var  Model $model
             */
            $model = new $model_namespace();

            $data = Faker::mock($attrs, function ($attr, $value) use ($img_field, $http_field, $img_src, $http_url) {
                $field = $attr['Field'];
                if (in_array($field, $img_field)) {
                    return Faker::random($img_src);
                }
                if (in_array($field, $http_field)) {
                    return Faker::random($http_url);
                }
                return $value;
            });

            $model->save($data);

            if ($model->id) {
                $success++;
            }
        }

        return $success;
    }
}